package com.iknowone.db;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.bson.types.ObjectId;

import com.google.code.geocoder.Geocoder;
import com.google.code.geocoder.GeocoderRequestBuilder;
import com.google.code.geocoder.model.GeocodeResponse;
import com.google.code.geocoder.model.GeocoderRequest;
import com.google.code.geocoder.model.GeocoderResult;
import com.google.code.geocoder.model.LatLng;
import com.iknowone.entity.Category;
import com.iknowone.entity.Contact;
import com.iknowone.entity.Coordinate;
import com.iknowone.entity.DbCollDef;
import com.iknowone.entity.DbFieldDef;
import com.iknowone.entity.Poi;
import com.iknowone.entity.PoiInfo;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoException;

public class Dao {

	public void addRating(DB db, DBObject objectToSave) throws MongoException {
		DBCollection col = db.getCollection(DbCollDef.RATINGS.getValue());
		if (col != null) {
			col.insert(objectToSave);
		}
	}

	public List<Poi> lastRecomandations(DB db, Integer limit) {
		List<Poi> pois = new ArrayList<>();
		List<String> poiIds = new ArrayList<>();
		DBCollection col = db.getCollection(DbCollDef.RATINGS.getValue());
		DBObject sortObj = new BasicDBObject();
		sortObj.put(DbFieldDef.STARS.getValue(), -1);
		DBCursor cursor = col.find().limit(limit).sort(sortObj);
		while (cursor != null && cursor.hasNext()) {
			DBObject dbObject = cursor.next();
			poiIds.add((String) dbObject.get(DbFieldDef.POI_ID.getValue()));
		}
		// TODO - get pois
		return pois;
	}

	public List<Poi> search(DB db, String category) {
		List<Poi> pois = new ArrayList<>();
		DBCollection col = db.getCollection(DbCollDef.POI.getValue());
		DBObject searchObj = new BasicDBObject();
		Pattern regex = Pattern.compile(category);
		searchObj.put("categories.name", regex);
		DBCursor cursor = col.find(searchObj);
		while (cursor != null && cursor.hasNext()) {
			DBObject dbObject = cursor.next();
			pois.add(buildPoi(dbObject));
		}
		return pois;
	}

	private Poi buildPoi(DBObject dbObject) {
		Poi poi = null;
		ObjectId id = (ObjectId) dbObject.get("_id");
		String name = (String) dbObject.get("name");
		DBObject contactObj = (DBObject) dbObject.get("contact");
		String address = (String) contactObj.get("address");
		Contact contact = new Contact(null, address, null);
		DBObject detailsObj = (DBObject) dbObject.get("details");
		String schedule = (String) detailsObj.get("schedule");
		PoiInfo poiInfo = new PoiInfo(schedule);
		List<Category> categories = new ArrayList<>();
		BasicDBList categoryObj = (BasicDBList) dbObject.get("categories");
		Iterator iterator = categoryObj.iterator();
		while (iterator.hasNext()) {
			DBObject category = (DBObject) iterator.next();
			String catId = (String) category.get("id");
			String catName = (String) category.get("name");
			String catParent = (String) category.get("parent");
			categories.add(new Category(Long.parseLong(catId), catName,
					catParent));
		}
		poi = new Poi(id.toString(), name, contact, categories, poiInfo, null,
				null, 2, null);
		try {
			poi.setCoordinate(geocode(poi.getContact().getAddress()));
		} catch (Exception e) {
			System.out.println(poi.getContact().getAddress());
		}
		return poi;
	}

	public Coordinate geocode(String address) {
		Geocoder geocoder = new Geocoder();
		GeocoderRequest geocoderRequest = new GeocoderRequestBuilder()
				.setAddress("Paris, France").setLanguage("en")
				.getGeocoderRequest();
		GeocodeResponse geocoderResponse = geocoder.geocode(geocoderRequest);
		GeocoderResult result = geocoderResponse.getResults().get(0);
		LatLng latlng = result.getGeometry().getLocation();
		Coordinate coord = new Coordinate(Double.parseDouble(latlng.getLat()
				+ ""), Double.parseDouble(latlng.getLng() + ""));
		return coord;
	}
}